package com.ayg.tools.exec.timer;


import com.alibaba.fastjson.JSON;

import org.springframework.web.context.request.ServletWebRequest;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @Description： 执行时长记录
 */
public class ExecTime {

    private static final ThreadLocal<Map<String, Long>> costTimeLocal = new ThreadLocal<Map<String, Long>>();

    /**
     * 存储数据到线程中
     */
    private static final ThreadLocal<Map<String, Object>> paramThreadLocal = new ThreadLocal<Map<String, Object>>();
    private static final String ST_FIX = "ST_"; //开始时间
    private static final String ET_FIX = "ET_"; //结束时间

    private ExecTime() {
        //just for private
    }

    private static Map<String, Object> getParamThreadLocal(){
        Map<String, Object> map = paramThreadLocal.get();
        if (null == map){
            map = new HashMap<>();
            paramThreadLocal.set(map);
        }
        return map;
    }

    public static void start(String key) {
        try {
            Map<String, Long> map = costTimeLocal.get();
            if (map == null) {
                map = new HashMap<>();
                costTimeLocal.set(map);
            }
            map.put(ST_FIX + key, System.currentTimeMillis());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }


    public static void end(String key) {
        try {
            costTimeLocal.get().put(ET_FIX + key, System.currentTimeMillis());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 打印参数
     * @param obj
     */
    public static void printArgs(String className,String methodName,Object[] obj){
        getParamThreadLocal().put("args",obj);
        //System.out.println("方法参数：" + className + "#" + methodName + " args：" + JSON.toJSONString(obj));

        if (obj.length == 5){
            if (obj[4] instanceof Exception){
                Exception e = (Exception) obj[4];
                e.printStackTrace();
            }
        }
    }


    /**
     * 打印返回值
     * @param ret
     */
    public static void printRet(Object ret,String printRet,String className,String methodName) {
        if (Boolean.valueOf(printRet)) {
            getParamThreadLocal().put("return", ret);
            //System.out.println("方法返回值：" + JSON.toJSON(ret));
        }
        getParamThreadLocal().put("className", className);
        getParamThreadLocal().put("methodName", methodName);

        // 对于jdbc PreparedStatement 类的 execute 不进行输出，避免输出过多
        if (className.contains("PreparedStatement") && methodName.equals("execute")){
            return;
        }

        System.out.println("-----------------------------");
        //System.out.println("    " + "方法名：" + className + "#" + methodName);
        if (getParamThreadLocal().containsKey("request")){
            ServletWebRequest request = (ServletWebRequest) getParamThreadLocal().get("request");
            javax.servlet.http.HttpServletRequest servletRequest = request.getRequest();
            System.out.println("    请求路径URL：" + servletRequest.getRequestURL());
            System.out.println("    请求ip：" + servletRequest.getRemoteAddr());
            System.out.println("    请求方式：" + servletRequest.getMethod());
        }
        if (getParamThreadLocal().containsKey("method")){
            Method method = (Method) getParamThreadLocal().get("method");
            System.out.println("    处理方法：" + method.getDeclaringClass().getName() + "#" + method.getName());
        }
        if (getParamThreadLocal().containsKey("args")) {
            try{
                System.out.println("    " + "方法参数：" + JSON.toJSONString(getParamThreadLocal().get("args")));
            }catch (Exception e){
                System.out.println("    方法参数：" + "打印失败：" + e.getMessage());
            }
        }
        if (getParamThreadLocal().containsKey("execTime")) {
            System.out.println("    " + "方法执行耗时：" + getParamThreadLocal().get("execTime") + " ms");
        }
        if (getParamThreadLocal().containsKey("return")) {
            try {
                System.out.println("    " + "方法返回值：" + JSON.toJSONString(getParamThreadLocal().get("return")));
            }catch (Exception e){
                System.out.println("    方法返回值：" + "打印失败：" + e.getMessage());
            }

        }
        if (!getParamThreadLocal().containsKey("sql")) {
            getParamThreadLocal().put("sql",new ArrayList<>());
        }
        List<String> sqls = (List<String>) getParamThreadLocal().get("sql");
        System.out.println("    " + "方法执行过的sql：共（"+sqls.size()+"）条");
        for (String sql : sqls) {
            System.out.println("        " + sql + ";");
        }
        System.out.println("-----------------------------");
    }

    /**
     * 打印sql语句
     * @param sql
     */
    public static void printJdbcSql(String sql){
        String replace =  sql.replace("\r", "").replace("\n", "").replace("\r\n", "").replace("  "," ");
        Map<String, Object> paramThreadLocal = getParamThreadLocal();
        if (!paramThreadLocal.containsKey("sql")){
            paramThreadLocal.put("sql",new ArrayList<>());
        }
        List sqlList = (List) paramThreadLocal.get("sql");
        sqlList.add(replace);

        /*System.out.println("---------------------------");
        System.out.println("    " + replace);
        System.out.println("---------------------------");*/
    }

    /**
     * 打印springmvc真正处理请求方法的参数值
     * @param obj
     */
    public static void printTemp(Object obj){
        getParamThreadLocal().put("args",obj);
        try {
            //System.out.println("临时打印：" + JSON.toJSONString(obj));
        }catch (Exception e){

        }
    }

    /**
     * 打印springmvc真正处理请求的方法
     * @param method
     */
    public static void printMethod(Method method){
        //System.out.println("method：" + method.getName());
        getParamThreadLocal().put("method",method);
    }

    public static void printRequest(Object request){
        getParamThreadLocal().put("request",request);
    }


    /**
     * 打印执行时间
     * @param className
     * @param methodName
     * @param methodDesc
     */
    public static void execTime(String className, String methodName, String methodDesc) {
        try {
            String key = className + methodName + methodDesc;
            long costTime = costTimeLocal.get().get(ET_FIX + key) - costTimeLocal.get().get(ST_FIX + key);
            //System.out.println(className.replace("/", ".") + "." + methodName + " cost:" + costTime + "ms");

            getParamThreadLocal().put("execTime",costTime);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
